package kb;

import kb.TBox;

import java.util.*;
import java.util.Map.Entry;

import entities.concept.Concept;
import entities.concept.NotConcept;
import entities.concept.PConcept;

import preprocessor.absorption.Absorption;

/**
 * Find out all the told subsumer and subsumee of a concept, etc.
 * 
 * @author j55wu
 * 
 */
public class SimpleReasoning {

	private TBox tb;
	private static HashMap<Concept, HashSet<Concept>> superClasses; // cache all
																	// told
																	// super
																	// classes
	private static HashMap<Concept, HashSet<Concept>> subClasses; // cache all
																	// told sub
																	// classes

	static {
		superClasses = new HashMap<Concept, HashSet<Concept>>();
		subClasses = new HashMap<Concept, HashSet<Concept>>();
	}

	public SimpleReasoning(TBox tb) {
		this.tb = tb;
	}

	public HashSet<Concept> givenSuperclasses(Concept c) {
		if (c.isTop()) {
			return new HashSet<Concept>();
		}
		if (superClasses.containsKey(c)) {
			return superClasses.get(c);
		}
		HashSet<Concept> superclasses = new HashSet<Concept>();
		superclasses.add(c);// of course c->c.
		Concept cc = null;
		if (c instanceof PConcept && tb.getTu().containsKey(c)) {
			cc = tb.getTu().get(c);
		} else if (c.isBinarySimple() && tb.getTb().containsKey(c)) {
			cc = tb.getTb().get(c);
		} else if (c instanceof NotConcept && tb.getTnu().containsKey(c)) {
			cc = tb.getTnu().get(c);
		}
		if (c != null) {
			superclasses.add(cc);
		}
		// if the given concept is not within the absorbed axioms, try GCIs as
		// well
		if (tb.getTg().containsKey(c)) {
			// cc = tb.getTg().get(c);
			superclasses.add(cc);
		}
		// recursive operations
		// if(cc != null)
		// superclasses.addAll(givenSuperclasses(cc));
		superClasses.put(c, superclasses);
		return superclasses;
	}

	/**
	 * To do: to recursively get all the subclasses of the given concept At
	 * present should only the direct subclasses be considered for efficiency?
	 * by J.W.
	 * 
	 * @param c
	 * @return
	 */
	public HashSet<Concept> givenSubclasses(Concept c) {
		if (subClasses.containsKey(c)) {
			return subClasses.get(c);
		}
		HashSet<Concept> subclasses = new HashSet<Concept>();
		subclasses.add(c);// of course c->c.
		// HashSet<Concept> recursions = new HashSet<Concept>();
		if (Absorption.CA && this.tb.getTu().values().contains(c)) {
			// if c has some sub classes in Tu.
			HashSet<Concept> temp = this.getKeysFromValue(this.tb.getTu(), c);
			subclasses.addAll(temp);
			// recursions.addAll(temp);
		}
		if (Absorption.BA && this.tb.getTb().values().contains(c)) {
			HashSet<Concept> temp = this.getKeysFromValue(this.tb.getTb(), c);
			subclasses.addAll(temp);
			// recursions.addAll(temp);
		}
		if (Absorption.NCA && this.tb.getTnu().values().contains(c)) {
			HashSet<Concept> temp = this.getKeysFromValue(this.tb.getTnu(), c);
			subclasses.addAll(temp);
			// recursions.addAll(temp);
		}
		if (this.tb.getTg().values().contains(c)) {
			HashSet<Concept> temp = this.getKeysFromValue(this.tb.getTg(), c);
			subclasses.addAll(temp);
			// recursions.addAll(temp);
		}
		// recursive operations
		// if(recursions.size()>0){
		// for(Concept cc:recursions){
		// subclasses.addAll(this.givenSubclasses(cc));
		// }
		// }
		subClasses.put(c, subclasses);
		return subclasses;
	}

	/*
	 * Given a value, get a list/set of keys mapped to the value.
	 */
	public HashSet<Concept> getKeysFromValue(Map<?, ?> map, Concept value) {
		HashSet<Concept> keys = new HashSet<Concept>();
		for (Entry<?, ?> o : map.entrySet()) {
			if (o.getValue().equals(value)) {
				if (o.getKey() instanceof Concept) {
					keys.add((Concept) o.getKey());
				}
				// else if(o.getKey() instanceof HashSet){
				// /**
				// * Note that A and B -> C, A is not a subclass of C, neither B
				// is.
				// */
				// for(Object oo:(HashSet<?>)o.getKey()){
				// keys.add((Concept) oo);
				// }
				// }
			}
		}
		return keys;
	}

}
